#!/bin/bash
#
# Copyright (C) 2008-2014 by Robert Cotrone & Dan Landon
#
# This file is part of the Powerdown package for unRAID.
#
# Powerdown is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Powerdown is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Powerdown.  If not, see <http://www.gnu.org/licenses/>.
#
# Stop unRAID.
#
VERSION="2.10"

# be sure rc.unRAID is not run twice
if [ -f /var/run/rc.unRAID.pid ]
   then logger "rc.unRAID already active, this one is exiting"
	exit
   else echo $$ > /var/run/rc.unRAID.pid
fi

trap "rm -f /var/run/rc.unRAID.pid" EXIT HUP INT QUIT

[ ${DEBUG:=0} -gt 0 ] && set -x -v

P=${0##*/}              # basename of program
R=${0%%$P}              # dirname of program

# Set Your LOG directory here
LOGDIR=/boot/logs/

# Set amount of syslogs you want to keep.
# Number of syslogs to save in logdir
LOGSAVE="10"

# read in the configuration file if there is one for LOGDIR and LOGSAVE
if [ -f /boot/config/plugins/powerdown/powerdown.conf ]
then
   fromdos < /boot/config/plugins/powerdown/powerdown.conf > /tmp/powerdown.conf
   chmod u+x /tmp/powerdown.conf
   source /tmp/powerdown.conf
   rm -f /tmp/powerdown.conf
fi

# If the LOG directory does not exist, make it!
[ ${LOGSAVE} -ne "0" ] && [ ! -d ${LOGDIR} ] && mkdir -p ${LOGDIR}

PATH=$PATH:/sbin:/usr/sbin:/boot/custom/bin

# directory for K and S script processing
RC_DIR=/etc/rc.d/rc.unRAID.d/

# directory to flash drive cached K and S scripts
POWERDOWNHOME=/boot/config/plugins/powerdown/rc.unRAID.d/

# Alter this to NO or anything other then YES
# To disable calls to these diagnostics
SMARTCTL=${SMARTCTL:=YES}
HDPARM=${HDPARM:=YES}

# Source external file to replace anything that is defined
if [ -f /etc/${P} ]
   then source /etc/${P}
fi

# no matter what.  Start from known directory
cd /

unRAID_version()
{
	echo "Powerdown V$VERSION"
}

logger()
{
  typeset F=${1##-t*}
  if [ "${F}" != "${1}" ]
     then F=""
     else F="-t${P}[$$]"
  fi

  /usr/bin/logger -i -plocal7.info ${F} $*
}

diagnostic_dump()
{
    echo "Capturing information to syslog. Please wait..."

    logger -tversion -s < /proc/version
    logger -tversion -s < /etc/unraid-version
    logger -tcmdline    < /proc/cmdline
    logger -tmeminfo    < /proc/meminfo
    logger -tdevices    < /proc/devices
    logger -tinterrupts < /proc/interrupts
    logger -tioports    < /proc/ioports
    logger -tdma        < /proc/dma
    logger -tmounts     < /proc/mounts
    logger -tdiskstats  < /proc/diskstats

    egrep -i 'model name|MHz|cache|bogo|flags' < /proc/cpuinfo \
	  | sed 's/\t//g' | logger -tcpuinfo

    if [ "${HDPARM}" = "YES" ] ; then
       ls -1 /dev/[hs]d[a-z] | while read DEVICE
       do hdparm -I -i ${DEVICE}
       done 2>&1 | sed 's/\t/        /g' | logger -tsmartctl
    fi

    if [ "${SMARTCTL}" = "YES" ] ; then
       ls -1 /dev/[hs]d[a-z] | while read DEVICE
       do smartctl -n standby -d ata -a ${DEVICE}
       done 2>&1 | sed 's/\t/        /g' | logger -tsmartctl
    fi

    lspci          2>&1 | logger -tpspci
    lsmod          2>&1 | logger -tlsmod
    ifconfig eth0  2>&1 | logger -tifconfig

    ( ethtool eth0 ; ethtool -S eth0 ) |
      sed 's/\t/        /g' 2>&1 | logger -tethtool

    BC=/boot/config
    for FILE in ${BC}/*.cfg ${BC}/shares/*
    do  BFILE="${FILE##*/}"  # Basename of FILE
        logger -t"${BFILE}" < "${FILE}"
    done

    if [ -e /proc/mdcmd ]
       then echo status > /proc/mdcmd
            sleep 1
            logger -tmdcmd < /proc/mdcmd
    fi

    unRAID_status       | logger -tstatus -s
}

save_syslog()
{
	if [ ${LOGSAVE} -ne "0" ]
	then
		TS="%Y%m%d-%H%M%S"
		LOGDATE=`ls -l --time-style="+${TS}" /var/log/syslog | cut -d' ' -f6`
		LOGNAME="${LOGDIR}syslog-${LOGDATE}.txt"

		# Save only the $LOGSAVE number of current files
		# save all logs if -1
		if [ ${LOGSAVE} -ne "-1" ]
		then
			i=0
			ls -1t ${LOGDIR}syslog*.txt | while read SYSLOG
			do  ((i++))
				if [ $i -gt ${LOGSAVE} ]
				   then echo "Removing old syslog: ${SYSLOG}"
						rm -f ${SYSLOG}
				fi
			done
		fi

		echo "Saving current syslog: ${LOGNAME}"
		todos < /var/log/syslog > "${LOGNAME}"
		touch --reference=/var/log/syslog ${LOGNAME}
		chmod a-x ${LOGNAME}

		# Save latest syslog in a .zip archive for uploading
		# logger "zipping current syslog to ${LOGDIR}syslog.zip"
		# only zip a new syslog.txt if syslog newer then current .zip

		if [ ! -x /usr/bin/zip ]
		   then echo "zip not installed. Consider installing to automatically zip current syslog"
				return
		fi

		if [ /var/log/syslog -nt ${LOGDIR}syslog.zip ]
		   then cd /var/log
				# make a symlink to syslog.txt for windows viewing
				ln -s  syslog syslog.txt
				rm -f  ${LOGDIR}syslog.zip
				# -o (set .zip time to mtime of syslog)
				# -l (convert lf to crlf on the fly!)
				zip -o -l ${LOGDIR}syslog.zip syslog.txt
				rm -f  syslog.txt  # remove symlink
				chmod a-x ${LOGDIR}syslog.zip # remove samba attributes
		fi
	fi
}

# check for any active pids on the array
unRAID_pid_check()
{
    # find active pids on array save to tmp file
    # so size (-s) can be tested and print if > 0
    PSTMP="/tmp/ps.$$"
	/usr/bin/fuser -mv /mnt/disk* /mnt/cache /mnt/user/* /dev/md* 2>/dev/null > ${PSTMP}

    if [ -s "${PSTMP}" ]
       then echo -e "Active PIDS on the array"
       else echo -e "No active PIDS on the array"
    fi
    rm -f ${PSTMP}
}

# Start unraid:
unRAID_start()
{
    logger "Processing $RC_DIR start scripts."

    # run start scripts in the /etc/rc.d/rc.unRAID.d directory
    find ${RC_DIR} -type f -name 'S[0-9][0-9]*' | sort | while read script
    do  if [ -x ${script} ] ; then
           logger Running: \"${script}\"
           ${script} 2>&1 | logger
       fi
    done
}

# Stop unraid:
unRAID_stop()
{
	logger "Powerdown V$VERSION"

    logger "Stopping Plugins."

	# add in any user skip files
	if [ -f /boot/config/plugins/powerdown/rcdskip ]
	then
		fromdos </boot/config/plugins/powerdown/rcdskip >/var/tmp/rcdskip
		cat /var/tmp/rcdskip >> /etc/rc.d/rcdstock
	fi

    # files only - do not include directories.
    comm -13 <(sort -u < "/etc/rc.d/rcdstock") <(ls -p "/etc/rc.d" | grep -v "/") |	while read LINE
    do  [ -z "${LINE}" ] && continue
		# only if executable, not .bak, and not .swp
		if [ -x "/etc/rc.d/${LINE}" ] && ! [[ "${LINE}" =~ ".bak" ]] && ! [[ "${LINE}" =~ ".swp" ]]
		then
			logger Running: \"/etc/rc.d/${LINE} stop\"
			/etc/rc.d/${LINE} stop | logger
		fi
	done

    logger "Stopping unRAID."

    [ -x /etc/rc.d/rc.docker ] && /etc/rc.d/rc.docker stop
    [ -x /etc/rc.d/rc.samba  ] && /etc/rc.d/rc.samba  stop
    [ -x /etc/rc.d/rc.nfsd   ] && /etc/rc.d/rc.nfsd   stop
    [ -x /etc/rc.d/rc.atalk  ] && /etc/rc.d/rc.atalk  stop

    swapoff -av 2>&1  | logger

    mount | grep loop | while read FS THE_REST
    do   umount -vf $FS;
    done 2>&1 | logger

    if [ -x /root/mdcmd ]
	then
		if [ -n "`/root/mdcmd status | grep "mdState=STARTED"`" ]
		then
			echo "Killing active pids on the array drives"
			logger "Killing active pids on the array drives"
			/usr/bin/fuser -k /mnt/user/* /mnt/disk* /mnt/cache /dev/md* 2>&1 | logger

			echo "Sync filesystems"
			logger "Sync filesystems"
			sync

			echo "Unmounting the drives"
			logger "Umounting the drives"
			for disk in /dev/md*
			do  /bin/umount -vf ${disk}
			done 2>&1 | logger

		    PSTMP="/tmp/ps.$$"
			/usr/bin/fuser -mv /dev/md* 2>&1 > ${PSTMP}
		    if [ -s "${PSTMP}" ]
			then
				logger "Active pids left on the array drives"
				/usr/bin/fuser -mv /dev/md* 2>&1 | logger
			fi

			echo "Stopping the Array"
			logger "Stopping the Array"
			/root/mdcmd status | tr -d '\000' > /tmp/mdcmd.$$.1
			/root/mdcmd stop 2>&1 | logger
			sleep 5
			/root/mdcmd status | tr -d '\000' > /tmp/mdcmd.$$.2
			diff -u /tmp/mdcmd.$$.1 /tmp/mdcmd.$$.2 | logger -t mdstatusdiff
			rm   -f /tmp/mdcmd.$$.1 /tmp/mdcmd.$$.2
		else
			echo "Array Stopped"
			logger "Array Stopped"
		fi
 	else
		echo "Cannot run /root/mdcmd"
		logger "Cannot run /root/mdcmd"
    fi

	echo "Saving syslog"
    save_syslog

	# Be sure the flash drive completes its writes
	sync
	sleep 2
}

# process user kill scripts in $RC_DIR
unRAID_kill()
{
    logger "Processing $RC_DIR kill scripts."

    # run kill scripts in the /etc/rc.d/rc.unRAID.d directory
    find ${RC_DIR} -type f -name 'K[0-9][0-9]*' | sort | while read script
    do  if [ -x ${script} ] ; then
           logger Running: \"${script}\"
           ${script} 2>&1 | logger
        fi
    done
}

# update rc.unRAID.rc scripts
unRAID_update()
{
	echo "Updating $RC_DIR scripts from flash drive"

	# remove the 'K' and 'S' files before we update
	find ${RC_DIR} \( -name 'K*' -o -name 'S*' \) -delete

	# copy the K scripts from the flash
	find ${POWERDOWNHOME} -type f -name 'K[0-9][0-9]*' | sort | while read script
	do  if [ -x ${script} ] ; then
		   fromdos < ${script} > ${RC_DIR}${script##*/}
		   chmod +x ${RC_DIR}${script##*/}
		fi
	done

	# copy the S scripts from the flash
	find ${POWERDOWNHOME} -type f -name 'S[0-9][0-9]*' | sort | while read script
	do  if [ -x ${script} ] ; then
		   fromdos < ${script} > ${RC_DIR}${script##*/}
		   chmod +x ${RC_DIR}${script##*/}
		fi
	done
	# remove any *.bak files
	find ${RC_DIR} \( -name '*.bak' -o -name '*.BAK' \) -delete

	echo "Updated files:"
	ls ${RC_DIR}
}

load_mdstatus()
{
    [ ${DEBUG:=0} -gt 2 ] && set -x -v
    OFS="${IFS}"  # Save IFS

    MDCMDTMP="/tmp/mdcmd.$$"
    # create tmp output, set trap for rm on exit
    touch ${MDCMDTMP}
    trap "rm -f ${MDCMDTMP}" EXIT HUP INT QUIT TERM

    # save status command
    # if $1 is defined, use that, otherwise use /proc/mdcmd
    # this is for testing using a saved or static output of mdcmd
    if [ ! -z "${1}" ]
       then MDCMD="${1}"
       else MDCMD="/proc/mdcmd"
            [ -e ${MDCMD} ] && echo status > ${MDCMD}
    fi
    if [ -e ${MDCMD} ]
       then cat < ${MDCMD} > ${MDCMDTMP}
       else echo "mdcmd; ${MDCMD} does not exist" >&2
    fi

    # Reset IFS to add = sign
    IFS=" = "

    # Read TMP file assigning shell variables from mdcmd variables
    MDI=0  # Set starting point for indexed variables
    while read LINE
    do  [ -z "${LINE}" ] && continue
        # LINE=`echo "${LINE}" | tr -d '\n'`
        VAR="${LINE%=*}"   # Separate var from var=value
        # separate value from var=value
        VALUE="${LINE#*=}"
        VARI="${VAR%\.*}"  # separate .#  from var
        # echo "VAR=$VAR VARI=$VARI VALUE=$VALUE"
        if [ "${VARI}" = "${VAR}" ]
           then eval "${VAR}='${VALUE}'"
                continue
        fi
        MDI="${VAR#*\.}"
        eval "${VARI}[$MDI]='${VALUE}'"
    done < ${MDCMDTMP}

    rm -f ${MDCMDTMP}

    IFS="${OFS}"
}


# Show unRAID status;
unRAID_status()
{
    load_mdstatus $@
    printf "State: ${mdState}\n"
    if [ "${mdResyncPrcnt}" != "" ]
       then printf "Parity CHECK in progress, %s%% complete, est. finish in %s minutes.\n" "$mdResyncPrcnt" "$mdResyncFinish"
    fi
    typeset i=0
    printf "%-2s %15.15s / %-15.15s %-14s %-9.9s %s\n" "D#" "Model" "Serial" "Status" "Device" # "Type"
    while (( ${i} <= ${MDI} ))
    do
        printf "%-2s %15.15s / %-15.15s %-14s %-9.9s %s\n" "${i}" \
        "${rdevModel[$i]}" "${rdevSerial[$i]}" \
        "${rdevStatus[$i]}" "${rdevName[$i]}" # "${rdevType[$i]}"
        if [ "${rdevStatus[$i]}" = "DISK_WRONG" ]; then
           printf "   %15.15s-%-15.15s <-- was the old disk in slot %s\n" \
                  "${diskModel[$i]}" "${diskSerial[$i]}" "$i"
        fi
        (( i++ ))
    done

    if [ "${SMARTCTL}" = "YES" ]; then
       echo "SMART overall health assessment"
       ls -1 /dev/[hs]d[a-z] | while read DEVICE
       do echo -e "${DEVICE}: \c"
          # smartctl -n standby -H ${DEVICE} 2>&1 | egrep -v 'Home|===|^$|smartctl version|mandatory SMART' 
          smartctl -n standby -H ${DEVICE} 2>&1 | egrep -i 'Health'
       done
       echo
    fi

    # echo "Services which may be active on the Array"
    # [ -x /etc/rc.d/rc.samba ] && /etc/rc.d/rc.samba status
    # [ -x /etc/rc.d/rc.nfsd  ] && /etc/rc.d/rc.nfsd  status

	unRAID_pid_check
}

case "$1" in
    'version' ) unRAID_version;;
    'start'   ) unRAID_start;;
    'stop'    ) unRAID_stop;;
    'status'  ) unRAID_status;;
    'kill'    ) unRAID_kill;;
    'diag'    ) diagnostic_dump;;
	'syslog'  ) save_syslog;;
    'update'  ) unRAID_update;;
    'msg'     ) shift; logger $@;;
    *) echo "usage $0 version|start|stop|status|kill|diag|syslog|update|msg";;
esac

trap - EXIT HUP INT QUIT
rm -f /var/run/rc.unRAID.pid
